/******************************************************************************/
/* @ All Rights Reserved Copyright (C) 2015 broada,Ltd.                       */
/*                                                                            */
/*  NAME      = rmi_parse.c                                                   */
/*  NOTE      =                                                               */
/*  DATE      = 2015/06/19 by geyh                                            */
/******************************************************************************/
#include <stdio.h>
#include <stdlib.h>

#include "frcomm.h"
#include "frmem.h"
#include "frreport_comm.h"
#include "frrmi.h"

#include "rmi_parse.h"

int rmi_skip_string(Frbyte_Packet *p_st_data)
{
    int i_ret = FR_SUCC;
    unsigned short us_data_len = 0;
    
    if(p_st_data == NULL)
        return FR_FAIL;
    
    i_ret = bytebuff_get_short(p_st_data, 2, &us_data_len, BYTE_BIG_ENDIAN);
    if(i_ret == FR_FAIL)
        return FR_FAIL;
    
    i_ret = bytebuff_skip(p_st_data, us_data_len);
    
    return i_ret;
    
}

/*******************************************************************************
*  FUNC     :  protocol
*  ARGS     :  p_st_data                解析数据
*           :
*  RTN      :  APM_L7_IS_NO
*           :  APM_L7_IS_YES
*  NOTE     :
*******************************************************************************/
int rmi_skip_protocol(Frbyte_Packet *p_st_data)
{
    int i_ret = FR_SUCC;
    unsigned char uc_tmp;

    if(p_st_data == NULL)
        return FR_FAIL;

    i_ret = bytebuff_get_char(p_st_data, (uint8_t *)&uc_tmp);
    if(i_ret == FR_FAIL)
        return FR_FAIL;

    switch (uc_tmp)
    {
        case '\x4b':
            return FR_SUCC;
            break;

        case '\x4c':
            return FR_SUCC;
            break;

        case '\x4d':
            return FR_SUCC;
            break;

        case '\x4e':
            return FR_SUCC;
            break;

        case '\x4f':
            return FR_SUCC;
            break;

        default:
            return FR_FAIL;
    }
}


/*******************************************************************************
*  FUNC     :  magic
*  ARGS     :  p_st_data                解析数据
*           :
*  RTN      :  APM_L7_IS_NO
*           :  APM_L7_IS_YES
*  NOTE     :
*******************************************************************************/
int rmi_skip_magic(Frbyte_Packet *p_st_data)
{
    char arr_tmp[5];
    int i_ret = FR_SUCC;

    if(p_st_data == NULL)
        return FR_FAIL;

    //取得内容
    i_ret = bytebuff_get_bytes(p_st_data, arr_tmp, 4);
    if(i_ret == FR_FAIL)
        return FR_FAIL;

    if(memcmp(arr_tmp, "JRMI", 4) != 0)
        return FR_FAIL;

    return FR_SUCC;

}

/*******************************************************************************
*  FUNC     :  stream magic
*  ARGS     :  p_st_data                解析数据
*           :
*  RTN      :  APM_L7_IS_NO
*           :  APM_L7_IS_YES
*  NOTE     :
*******************************************************************************/
int rmi_skip_magic2(Frbyte_Packet *p_st_data)
{
    int i_ret = FR_SUCC;
    char arr_tmp[3];

    if(p_st_data == NULL)
        return FR_FAIL;

    //取得内容
    i_ret = bytebuff_get_bytes(p_st_data, arr_tmp, 2);
    if(i_ret == FR_FAIL)
        return FR_FAIL;

    if(memcmp(arr_tmp, "\xac\xed", 2) != 0)
        return FR_FAIL;

    return FR_SUCC;
}


/*******************************************************************************
*  FUNC     :  version
*  ARGS     :  p_st_data                解析数据
*           :  p_st_private             私有数据
*           :
*  RTN      :  APM_L7_IS_NO
*           :  APM_L7_IS_YES
*  NOTE     :
*******************************************************************************/
int rmi_parse_version(Frbyte_Packet *p_st_data, L7session_rmi_private *p_st_private)
{
    int i_ret = FR_SUCC;
    unsigned short us_version = 0;
    char arr_tmp[16];

    if(p_st_data == NULL || p_st_private == NULL)
        return FR_FAIL;

    //判断是否为JRMI
    i_ret = rmi_skip_magic(p_st_data);
    if(i_ret == FR_FAIL)
        return FR_FAIL;

    i_ret = bytebuff_get_short(p_st_data, 2, (uint16_t *)&us_version, BYTE_BIG_ENDIAN);
    if(i_ret == FR_FAIL)
        return FR_FAIL;

    i_ret = rmi_skip_protocol(p_st_data);
    if(i_ret == FR_FAIL)
        return FR_FAIL;

    //存取server
    snprintf(arr_tmp, sizeof(arr_tmp), "JRMI-%d", us_version);
    p_st_private->p_server = frstrdup(arr_tmp);
    if(p_st_private->p_server == NULL)
        return FR_FAIL;

    return FR_SUCC;
}

/*******************************************************************************
*  FUNC     :  protocol ack
*  ARGS     :  p_st_data                解析数据
*           :  p_st_body_data             上报信息链表
*           :
*  RTN      :  APM_L7_IS_NO
*           :  APM_L7_IS_YES
*  NOTE     :
*******************************************************************************/
int rmi_parse_protocolack(Frbyte_Packet *p_st_data)
{
    int i_ret = FR_SUCC;

    if(p_st_data == NULL)
        return FR_FAIL;

    i_ret = rmi_skip_protocol(p_st_data);
    if(i_ret == FR_FAIL)
        return FR_FAIL;

    //ip
    i_ret = rmi_skip_string(p_st_data);
    if(i_ret == FR_FAIL)
        return FR_FAIL;

    i_ret = bytebuff_skip(p_st_data, 4);

    return i_ret;
}

/*******************************************************************************
*  FUNC     :  continuation
*  ARGS     :  p_st_data                解析数据
*           :
*  RTN      :  APM_L7_IS_NO
*           :  APM_L7_IS_YES
*  NOTE     :
*******************************************************************************/
int rmi_parse_continuation(Frbyte_Packet *p_st_data)
{
    int i_ret = FR_SUCC;

    if(p_st_data == NULL)
        return FR_FAIL;

    //ip
    i_ret = rmi_skip_string(p_st_data);
    if(i_ret == FR_FAIL)
        return FR_FAIL;

    //port
    i_ret = bytebuff_skip(p_st_data, 4);

    return i_ret;
}

/*******************************************************************************
*  FUNC     :  calldata
*  ARGS     :  p_st_data                解析数据
*           :  p_st_body_data             上报信息链表
*           :
*  RTN      :  APM_L7_IS_NO
*           :  APM_L7_IS_YES
*  NOTE     :
*******************************************************************************/
int rmi_parse_calldata(Frbyte_Packet *p_st_data, Frreport_body_data *p_st_body_data, L7session_rmi_private *p_st_private)
{
    int i_ret = 0;
    int i_deep = 0;
    uint8_t uc_type = 0;
    rmiDataParent *p_rmi_head = NULL;
    rmiDataParent *p_rmi_root = NULL;
    uint32_t u32_passHandle = 0x007e0000;
    int i_pre = 0, i_now = 0;
    
    if(p_st_data == NULL || p_st_body_data == NULL)
        return FR_FAIL;
    
    i_ret = readStreamHeader(p_st_data);
    if(i_ret == FR_FAIL)
        return FR_FAIL;
    
    i_ret = bytebuff_peek_char(p_st_data, &uc_type);
    if(i_ret == FR_FAIL)
        return FR_FAIL;
    
    if(uc_type == TC_BLOCKDATA || uc_type == TC_BLOCKDATALONG)
    {
        i_ret = readBlockHeader(p_st_data);
        if(i_ret == FR_FAIL)
            return FR_FAIL;
    }
    
    i_now = bytebuff_remaining(p_st_data);
    //Object obj = readObject0(false);
    // if nested read, passHandle contains handle of enclosing object
    //class decs
    while (i_now)
    {
        if(i_now == i_pre)
            break;
        
        i_ret = readObject0(p_st_data, p_st_body_data, p_st_private->i_use_request, &i_deep, &p_rmi_head, &p_rmi_root, &u32_passHandle, NULL, (char *)"rmi");
        if(p_st_private->p_transaction_title == NULL)
        {
            if(p_rmi_root)
                p_st_private->p_transaction_title = frstrdup(p_rmi_root->p_name);
        }
    
        if(i_ret == FR_FAIL)
        {
            rmiHeadFree(p_rmi_root);
            return FR_SUCC;
        }
    
        if(p_rmi_head)
        {
            i_ret = rmi_report(p_st_data, p_st_body_data, p_st_private->i_use_request, &i_deep, p_rmi_head, &p_rmi_root
                               , &u32_passHandle, NULL, (char *)"rmi");
            if(i_ret == FR_FAIL)
                return FR_SUCC;
        }
        
        rmiHeadFree(p_rmi_root);
        p_rmi_root = NULL;
        p_rmi_head = NULL;
        
        i_pre = i_now;
        i_now = bytebuff_remaining(p_st_data);
        
    }

    return FR_SUCC;
}

/*******************************************************************************
*  FUNC     :  calldata
*  ARGS     :  p_st_data                解析数据
*           :  p_st_body_data             上报信息链表
*           :
*  RTN      :  APM_L7_IS_NO
*           :  APM_L7_IS_YES
*  NOTE     :
*******************************************************************************/
int rmi_parse_returndata(Frbyte_Packet *p_st_data, Frreport_body_data *p_st_body_data, L7session_rmi_private *p_st_private)
{
    int i_ret = 0;
    int i_deep = 0;
    uint8_t uc_type = 0;
    rmiDataParent *p_rmi_head = NULL;
    rmiDataParent *p_rmi_root = NULL;
    uint32_t u32_passHandle = 0x007e0000;
    int i_pre = 0, i_now = 0;

    if(p_st_data == NULL || p_st_body_data == NULL)
        return FR_FAIL;
    
    i_ret = readStreamHeader(p_st_data);
    if(i_ret == FR_FAIL)
        return FR_FAIL;
    
    i_ret = bytebuff_peek_char(p_st_data, &uc_type);
    if(i_ret == FR_FAIL)
        return FR_FAIL;
    
    if(uc_type == TC_BLOCKDATA || uc_type == TC_BLOCKDATALONG)
    {
        i_ret = readBlockHeader(p_st_data);
        if(i_ret == FR_FAIL)
            return FR_FAIL;
    }
    
    i_now = bytebuff_remaining(p_st_data);
    //Object obj = readObject0(false);
    // if nested read, passHandle contains handle of enclosing object
    //class decs
    while (i_now)
    {
        if(i_now == i_pre)
            break;
        
        i_ret = readObject0(p_st_data, p_st_body_data, p_st_private->i_use_request, &i_deep, &p_rmi_head, &p_rmi_root, &u32_passHandle, NULL, (char *)"rmi");
        if(i_ret == FR_FAIL)
        {
            rmiHeadFree(p_rmi_root);
            return FR_SUCC;
        }
        
        if(p_rmi_head)
        {
            i_ret = rmi_report(p_st_data, p_st_body_data, p_st_private->i_use_request, &i_deep, p_rmi_head, &p_rmi_root
                               , &u32_passHandle, NULL, (char *)"rmi");
            if(i_ret == FR_FAIL)
                return FR_SUCC;
        }
        
        rmiHeadFree(p_rmi_root);
        p_rmi_root = NULL;
        p_rmi_head = NULL;
        
        i_pre = i_now;
        i_now = bytebuff_remaining(p_st_data);
        
    }
    
    return FR_SUCC;
    
}

/*******************************************************************************
*  FUNC     :  数据解析主入口
*  ARGS     :  p_st_data                解析数据
*           :  p_st_body_data             上报信息链表
*           :
*  RTN      :  APM_L7_IS_NO
*           :  APM_L7_IS_YES
*  NOTE     :
*******************************************************************************/
int rmi_parse(Frbyte_Packet *p_st_data, Frreport_body_data *p_st_body_data, L7session_rmi_private *p_st_private)
{
    int i_ret = FR_SUCC;
    unsigned char uc_tmp;

    if(p_st_data == NULL || p_st_body_data == NULL || p_st_private == NULL)
        return APM_L7_ANALYZE_FAIL;

    i_ret = bytebuff_get_char(p_st_data, (uint8_t *)&uc_tmp);
    if(i_ret == FR_FAIL)
        return APM_L7_ANALYZE_FAIL;

    p_st_private->i_flag_needed = 1;

    if(p_st_private->i_flag_cont)
    {
        p_st_private->i_flag_cont = 2;
        return APM_L7_ANALYZE_SUCC;
    }

    switch(uc_tmp)
    {
        //version
        case '\x4a':
            if(p_st_private->i_flag_pre_data != 0)
                return APM_L7_ANALYZE_FAIL;

            p_st_private->i_flag_pre_data = 0x4a;
            p_st_private->i_flag_report = 0;
            break;

        //protocol ack
        case '\x4e':
            if(p_st_private->i_flag_pre_data != 0x4a)
                return APM_L7_ANALYZE_FAIL;

            p_st_private->i_flag_cont = 1;
            p_st_private->i_flag_report = 0;
            break;

        //not suport
        case '\x4f':
            if(p_st_private->i_flag_pre_data != 0x4a)
                return APM_L7_ANALYZE_FAIL;
            p_st_private->i_flag_report = 0;
            break;

        //call data
        case '\x50':
            p_st_private->i_flag_report = 1;
            i_ret = rmi_parse_calldata(p_st_data, p_st_body_data, p_st_private);
            if(i_ret == FR_FAIL)
                return APM_L7_ANALYZE_TODO;

            i_ret = frreport_body_l7_add_int(p_st_body_data, APM_REPORT_KEY_REQ_ISRESPREQUIRED, 1);
            if(i_ret == FR_FAIL)
                return APM_L7_ANALYZE_FAIL;

             i_ret = frreport_body_l7_add_str(p_st_body_data, APM_REPORT_KEY_TRANS_TITLE, p_st_private->p_transaction_title);
             if(i_ret == FR_FAIL)
                 return APM_L7_ANALYZE_FAIL;

            p_st_private->i_flag_pre_data = 0x50;
            break;

        //return data
        case '\x51':
            if(p_st_private->i_flag_pre_data != 0x50)
                return APM_L7_ANALYZE_FAIL;

            p_st_private->i_flag_report = 1;
            i_ret = rmi_parse_returndata(p_st_data, p_st_body_data, p_st_private);

            break;

        //ping
        case '\x52':
            p_st_private->i_flag_pre_data = 0x52;
            p_st_private->i_flag_report = 0;
            break;

        //ping ack
        case '\x53':
            if(p_st_private->i_flag_pre_data != 0x52)
                return APM_L7_ANALYZE_FAIL;
            p_st_private->i_flag_report = 0;
            p_st_private->i_flag_pre_data = 0x53;
            break;

        //dgcack
        case '\x54':
            p_st_private->i_flag_report = 0;

            break;

        default:
            return APM_L7_ANALYZE_FAIL;
    }

    return i_ret == FR_SUCC ? APM_L7_ANALYZE_SUCC : APM_L7_ANALYZE_TODO;
}
